package controller;

import java.util.List;

import javax.swing.JPanel;

import model.Project;
import modelInterfaces.IProject;
import pluginInterfaces.IMetric;
import pluginInterfaces.setup.MetricSetup;
import utils.weka.core.SerializedObject;
import utils.weka.view.GenericObjectEditor;
import view.ViewMetricsPanel;
import viewInterfaces.AbstractViewFactory;
import viewInterfaces.IViewTestsPanel;
import viewInterfaces.IViewRecommendersPanel;
import controllerInterfaces.IControllerMain;
import controllerInterfaces.IControllerMetricsPanel;

/**
 * Controls flow of information from panel of metrics configurations (Metrics Panel)   
 */
public class ControllerMetricsPanel implements IControllerMetricsPanel {

	/** MVC++ Main Controller
	 * * @see ControllerMain*/
	private IControllerMain controllerMain;
	
	/** View of Panel of Metrics
	 * @see ViewMetricsPanel*/
	private IViewTestsPanel view;
	
	/** Index of selected item from View
	 * @see ViewMetricsPanel*/
	private int indexToEdit;
	
	/**
	 * Class Constructor */
	public ControllerMetricsPanel(){
		this.view = AbstractViewFactory.getAbstractViewFactory().getViewMetricsPanel();
		this.view.SetController(this);
	}

	
	/**
	 * Set the MVC++ Main Class for this controller.</br>
	 * ControllerMain is manipulable through {@link IControllerMain} interface.
	 * @param	controllerMain	MVC++ Main Controller.
	 * @see	ControllerMain
	 * @see IControllerMain
	 */
	public void SetMainController(IControllerMain controllerMain) {
		this.controllerMain = controllerMain;
	}

	
	/**
	 * Get the Panel of View
	 * @return Panel of Metrics
	 * @see ViewMetricsPanel
	 */	
	public JPanel getPanel() {
		return this.view.GetPanel();
	}


	/**
	 * Start the metric setup for add a metric configuration ({@link Metric}) from Metrics Panel.
	 * @see Metric
	 * @see IMetric
	 */	
	public void addMetricSetup() {
		GenericObjectEditor.registerEditors();
		GenericObjectEditor goe = new GenericObjectEditor(false, this, false);
		goe.setClassType(IMetric.class);
		Object initial = new MetricSetup();
		goe.setValue(initial);
		this.view.renderDialogSetup(goe);		
	}


	/**
	 * Start the metric setup for edit a selected metric configuration ({@link Metric}) from Metrics Panel.
	 * @param	index	index of selected recommendation algorithm configuration.
	 * @see		Metric
	 * @see		IMetric
	 */		
	public void copyMetricSetup(int index) {
		IMetric metricOrig = this.controllerMain.getProject().getMetricList().get(index);
		IMetric metricCopy = null;
		
	    try
	    {
	    	SerializedObject so = new SerializedObject(metricOrig);
	    	metricCopy = (IMetric) so.getObject();
		}
	    catch (Exception e)
	    {
			e.printStackTrace();
		}
	    
	    metricCopy.setName(metricOrig.getName() + " - Copy of");
		this.addMetric(metricCopy);
	}	

	
	/**
	 * Start the metric setup for edit a selected recommendation algorithm configuration ({@link Metric}) from Recommenders Panel.
	 * @param	index	index of selected metric algorithm configuration.
	 * @see		Metric
	 * @see		IMetric
	 */	
	public void editMetricSetup(int index) {
		this.indexToEdit = index;
		GenericObjectEditor.registerEditors();
		GenericObjectEditor goe = new GenericObjectEditor(false, this, true);
		goe.setClassType(IMetric.class);
		goe.setValue(this.controllerMain.getMetricList().get(this.indexToEdit));
		this.view.renderDialogSetup(goe);
	}

	/**
	 * Remove the selected metric setup from Metrics Panel.</br>
	 * @param	index	index of selected metric configuration.
	 * @see 	Project
	 * @see		IProject
	 */	
	public void removeMetricSetup(int index) {
		this.controllerMain.removeMetricIntoTest(index);
		this.controllerMain.getProject().getMetricList().remove(index);
		this.controllerMain.StatusProjectModified();
		this.view.setMetricList(this.controllerMain.getProject().getMetricList());
		
	}
	
	
	/**
	 * Add the metric setup ({@link Metric}) by using Weka object.
	 * @param	m_Object	Object generated by Weka.
	 * @see		GenericObjectEditor
	 * @see 	Project
	 * @see		IProject
	 */	
	public void addMetric(Object m_Object) {
		this.controllerMain.getProject().getMetricList().add((IMetric) m_Object);
		this.controllerMain.StatusProjectModified();
		this.view.setMetricList(this.controllerMain.getProject().getMetricList());
	}

	
	/**
	 * Add the metric setup ({@link Metric}) to realize a copy. 
	 * @param	metric	Metric setup to be copied.
	 * @see		Metric
	 * @see		IMetric
	 * @see 	Project
	 * @see		IProject
	 */	
	private void addMetric(IMetric metric)
	{
		this.controllerMain.getProject().getMetricList().add(metric);
		this.view.setMetricList(this.controllerMain.getProject().getMetricList());
		this.controllerMain.StatusProjectModified();
	}

	
	/**
	 * Add the edited metric setup ({@link Metric}) by using Weka object.
	 * @param	m_Object	Object generated by Weka.
	 * @see		GenericObjectEditor
	 * @see 	Project
	 * @see		IProject
	 */		
	public void editMetric(Object m_Object) {
		IMetric prNew = (IMetric) m_Object;
		IMetric prOld = this.controllerMain.getProject().getMetricList().get(this.indexToEdit);
		prOld.setName(prNew.getName());
		
		this.controllerMain.getProject().getMetricList().set(this.indexToEdit, prOld);
		this.controllerMain.StatusProjectModified();
		this.view.setMetricList(this.controllerMain.getProject().getMetricList());
	}

	
	/**
	 * Block all visual components of panel.
	 * @see ViewMetricsPanel
	 */
	public void blockAllComponents() {
		this.view.setEnabledAll(false);	
	}

	
	/**
	 * Unblock all visual components of panel.
	 * @see ViewMetricsPanel
	 */	
	public void unBlockAllComponents() {
		this.view.setEnabledAll(true);	
	}
	
	
	/**
	 * Get the list of {@link Metric} from {@link ControllerMain}.</br>
	 * Each of the obtained {@link MEtric} are manipulable through its {@link IMetric} interface.
	 * @return	list of metric configurations.
	 * @see		ControllerMain
	 * @see		IControllerMain
	 * @see 
	 */	
	public List<IMetric> getMetricList() {
		return this.controllerMain.getMetricList();
	}

	
	/**
	 * Set the list of {@link Metric} from {@link ControllerMain}.</br>
	 * Each of the saved {@link Metric} are manipulable through its {@link IMetric} interface.
	 * @param	metricList	list of metric configurations.
	 * @see		ControllerMain
	 * @see		IControllerMain
	 */	
	public void setMetricList(List<IMetric> metricList) {
		this.view.setMetricList(metricList);
	}


	/**
	 * Get View of this controller</br>
	 * This method is only used for realize unit testing.
	 * @return IViewRecommendersPanel
	 */
	public IViewTestsPanel GetView()
	{
		return this.view;
	}	
	
}
